#pragma once
#include <shared_mutex>

#define RD_LOCK(mtx) std::shared_lock<std::shared_mutex> _RL(mtx)
#define WR_LOCK(mtx) std::unique_lock<std::shared_mutex> _WR(mtx)

class __MUTEX__
{
protected:

	std::shared_mutex	_M_mutex;
	explicit __MUTEX__() = default;
public:
	virtual ~__MUTEX__() = default;
	void r_lock()	{ _M_mutex.lock_shared(); }
	void r_unlock() { _M_mutex.unlock_shared(); }
	void w_lock()	{ _M_mutex.lock(); }
	void w_unlock() { _M_mutex.unlock(); }
	bool try_w_lock() { return _M_mutex.try_lock(); }
	bool try_r_lock() { return _M_mutex.try_lock_shared(); }
};

template<typename Ty>
class _MT_SAFE_ : public __MUTEX__
{
	Ty					_M_d;
public:
	_MT_SAFE_() = default;
	~_MT_SAFE_() = default;
	_MT_SAFE_(Ty const & rhs)
	{
		_M_d = rhs;
	}

	_MT_SAFE_<Ty>& operator=(_MT_SAFE_<Ty> const & rhs)
	{
		_M_d = rhs._M_d;
		return *this;
	}

	inline void set(Ty const & rhs)
	{
		WR_LOCK(_M_mutex);
		_M_d = rhs;
	}

	inline Ty& get()
	{
		RD_LOCK(_M_mutex);
		return _M_d;
	}

	inline Ty const get(Ty const & rhs)
	{
		WR_LOCK(_M_mutex);
		Ty tmp = _M_d;
		_M_d = rhs;
		return tmp;
	}

	inline Ty& _get()
	{
		return _M_d;
	}
};